﻿using rhIRC.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace rhIRC.Classes
{
    #region Delegates
    public delegate void ServerMessage(string ServerMessage);
    public delegate void CommandReceived(string IrcCommand);
    #endregion

    public class IRC
    {
        #region Private variables
        private TcpClient ircConnection;
        private NetworkStream ircStream;
        private StreamWriter ircWriter;
        private StreamReader ircReader;

        private Server server;
        private User user;
        private Channel channel;
        private bool isInvisible;
        private bool closeConnectionMessageReceived;

        private List<string> userInput;

        private Thread ircThread;
        #endregion

        #region Properties
        private bool isConnectionEstablished;
        public bool IsConnectionEstablished
        {
            get { return isConnectionEstablished; }
            set { isConnectionEstablished = value; }
        }

        private bool isUserAuthenticated;
        public bool IsUserAuthenticated
        {
            get { return isUserAuthenticated; }
            set { isUserAuthenticated = value; }
        }
        #endregion

        public IRC(Server server, User user, Channel channel)
        {
            this.server = server;
            this.user = user;
            this.channel = channel;
            this.isInvisible = false;

            userInput = new List<string>();
        }

        #region Events
        public event CommandReceived eventReceiving;
        public event ServerMessage eventServerMessage;

        private void IrcServerMessage(string[] IrcCommand)
        {
            string ServerMessage = "";

            for (int i = 0; i < IrcCommand.Length; i++)
            {
                ServerMessage += IrcCommand[i] + " ";
            }

            if (eventServerMessage != null) { this.eventServerMessage(ServerMessage.Trim()); }
        }
        #endregion

        #region Methods
        public void Connect()
        {
            this.closeConnectionMessageReceived = false;
            ircThread = new Thread(Loop);
            ircThread.Start();
        }

        public void Disconnect()
        {
            this.closeConnectionMessageReceived = true;
        }

        private void Loop()
        {
            this.ircConnection = new TcpClient(this.server.Adres, this.server.Port);
            this.ircStream = this.ircConnection.GetStream();
            this.ircReader = new StreamReader(this.ircStream);
            this.ircWriter = new StreamWriter(this.ircStream);

            IsConnectionEstablished = true;
            System.Console.WriteLine("Connection established");

            SendCommand(String.Format("USER {0} {1} * :{2}", Environment.MachineName, this.isInvisible == true ? "8" : "0", "rhIRC v0.1"));
            SendCommand(String.Format("NICK {0}", this.user.Name));
            SendCommand(String.Format("JOIN {0}", this.channel.Adres));

            IsUserAuthenticated = true;
            System.Console.WriteLine("User has been authenticated");

            while (!closeConnectionMessageReceived)
            {
                string ircCommand = ReadCommand();
                if (ircCommand != null)
                {
                    if (eventReceiving != null) { this.eventReceiving(ircCommand); }

                    string[] commandParts = new string[ircCommand.Split(' ').Length];
                    commandParts = ircCommand.Split(' ');
                    if (commandParts[0].Substring(0, 1) == ":")
                    {
                        commandParts[0] = commandParts[0].Remove(0, 1);
                    }

                    if (commandParts[0] == "PING")
                    {
                        // Server PING, send PONG back
                        this.IrcPing(commandParts);
                    }
                    else
                    {
                        this.IrcServerMessage(commandParts);
                    }
                }
            }

            this.ircWriter.Close();
            this.ircReader.Close();
            this.ircConnection.Close();

            IsConnectionEstablished = false;
            IsUserAuthenticated = false;

            System.Console.WriteLine("Disconnected");
        }

        private void IrcPing(string[] IrcCommand)
        {
            string PingHash = "";
            for (int intI = 1; intI < IrcCommand.Length; intI++)
            {
                PingHash += IrcCommand[intI] + " ";
            }
            SendCommand("PONG " + PingHash);
        }

        private void SendCommand(string command)
        {
            this.ircWriter.WriteLine(command);
            this.ircWriter.Flush();

            System.Console.WriteLine("C: " + command);
        }

        private string ReadCommand()
        {
            return this.ircReader.ReadLine();
        }

        public void ReadUserInput(string input)
        {
            if (IsConnectionEstablished && IsUserAuthenticated)
            {
                SendCommand(input);
            }
        }
        #endregion
    }
}
